/**
 * Copyright 2010 upTick Pty Ltd
 *
 * Licensed under the terms of the GNU General Public License version 3 
 * as published by the Free Software Foundation. You may obtain a copy of the
 * License at: http://www.gnu.org/copyleft/gpl.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations 
 * under the License.
 */

package au.com.uptick.serendipity.server.domain;

import javax.persistence.*;
import java.io.Serializable;

// Don't forget to add the add the following line to persistence.xml:
// <class>au.com.uptick.serendipity.server.domain.Account</class>

/*
 
   At the time of writing, the Hibernate JPA persistence provider has 
   some known issues that can cause problems in web applications such as 
   JavaServer Faces applications. While not specific to NetBeans, these
   issues can be worked around by choosing eager as the association fetch
   value and java.util.Set as the collection type in the Mapping Options pane.
   If you use the Hibernate JPA persistence provider and choose default or 
   lazy as the association fetch value in the Mapping Options pane, an 
   org.hibernate.LazyInitializationException exception can occur at runtime. 
   If you choose an association fetch value of eager and you do not also 
   choose java.util.Set as the collection type, an org.hibernate.HibernateException
   can occur (with the message "cannot simultaneously fetch multiple bags")
   at runtime. These issues pertain to the Hibernate JPA persistence provider
   and not to the default persistence provider. 
 
*/

@Entity
@Table(name = EntityTokens.ACCOUNT_TABLE)
public class Account implements Serializable {

    private static final long serialVersionUID = 8161681740825989132L;

    // When declaring instance variables in your POJOs always use the class type
    // e.g. Long rather than long.

    // Neither JPA nor Hibernate annotations support the notion of a default column value.
    // As a workaround to this limitation, set all default values just before you invoke
    // a Hibernate save() or update() on the session. This closely (short of Hibernate setting
    // the default values) mimics the behaviour of the database which sets default values
    // when it saves a row in a table.

    // Unlike setting the default values in the model class, this approach also ensures that
    // criteria queries that use an Example object as a prototype for the search will continue
    // to work as before. When you set the default value of a nullable attribute (one that has
    // a non-primitive type) in a model class, a Hibernate query-by-example will no longer ignore
    // the associated column where previously it would ignore it because it was null.

    @Id
    @Column(name = EntityTokens.ACCOUNT_ID_COLUMN)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long accountId;

    // @Version
    // @Column(name = EntityTokens.ACCOUNT_VERSION)
    // private Integer version;

    @Column(name = EntityTokens.ACCOUNT_NAME_COLUMN,
            length = EntityTokens.ACCOUNT_NAME_COLUMN_LENGTH)
    protected String accountName;

    @Column(name = EntityTokens.ACCOUNT_NUMBER_COLUMN,
            length = EntityTokens.ACCOUNT_NUMBER_COLUMN_LENGTH,
            nullable = EntityTokens.ACCOUNT_NUMBER_COLUMN_NULLABLE)
    protected String accountNumber;

    @Column(name = EntityTokens.PARENT_ACCOUNT_COLUMN,
            length = EntityTokens.PARENT_ACCOUNT_COLUMN_LENGTH,
            nullable = EntityTokens.PARENT_ACCOUNT_COLUMN_NULLABLE)
    protected String parentAccount;

    @Column(name = EntityTokens.PRIMARY_CONTACT_COLUMN,
            length = EntityTokens.PRIMARY_CONTACT_COLUMN_LENGTH,
            nullable = EntityTokens.PRIMARY_CONTACT_COLUMN_NULLABLE)
    protected String primaryContact;

    @Column(name = EntityTokens.EMAIL_PRIMARY_CONTACT_COLUMN,
            length = EntityTokens.EMAIL_PRIMARY_CONTACT_COLUMN_LENGTH,
            nullable = EntityTokens.EMAIL_PRIMARY_CONTACT_COLUMN_NULLABLE)
    protected String emailPrimaryContact;

    protected String relationshipType;

    // Electronic Address details
    @Column(name = EntityTokens.MAIN_PHONE_COLUMN,
            length = EntityTokens.MAIN_PHONE_COLUMN_LENGTH,
            nullable = EntityTokens.MAIN_PHONE_COLUMN_NULLABLE)
    protected String mainPhone;

    protected String fax;
    protected String otherPhone;
    protected String webSite;
    protected String email;

    // Address details
    protected String addressName;
    protected String addressLine1;
    protected String addressLine2;
    protected String addressLine3;

    @Column(name = EntityTokens.CITY_COLUMN,
            length = EntityTokens.CITY_COLUMN_LENGTH,
            nullable = EntityTokens.CITY_COLUMN_NULLABLE)
    protected String city;
    protected String state;
    protected String postalCode;
    protected String country;
    protected String addressType;

    public Account() {
    }

    public Account(Long accountId) {
        this.accountId = accountId;
    }

    /*

    public Account(AccountDto account) {
      // setAccountId(account.getAccountId());
      // ...
    }

    */

    public Long getAccountId() {
        return accountId;
    }

    public void setAccountId(Long accountId) {
        this.accountId = accountId;
    }

    public String getAccountName() {
        return accountName;
    }

    public void setAccountName(String accountName) {
        this.accountName = accountName;
    }

    public String getAccountNumber() {
        return accountNumber;
    }

    public void setAccountNumber(String accountNumber) {
        this.accountNumber = accountNumber;
    }

    public String getParentAccount() {
        return parentAccount;
    }

    public void setParentAccount(String parentAccount) {
        this.parentAccount = parentAccount;
    }

    public String getPrimaryContact() {
        return primaryContact;
    }

    public void setPrimaryContact(String primaryContact) {
        this.primaryContact = primaryContact;
    }

    public String getEmailPrimaryContact() {
        return emailPrimaryContact;
    }

    public void setEmailPrimaryContact(String emailPrimaryContact) {
        this.emailPrimaryContact = emailPrimaryContact;
    }

    public String getRelationshipType() {
        return relationshipType;
    }

    public void setRelationshipType(String relationshipType) {
        this.relationshipType = relationshipType;
    }

    public String getMainPhone() {
        return mainPhone;
    }

    public void setMainPhone(String mainPhone) {
        this.mainPhone = mainPhone;
    }

    public String getFax() {
        return fax;
    }

    public void setFax(String fax) {
        this.fax = fax;
    }

    public String getOtherPhone() {
        return otherPhone;
    }

    public void setOtherPhone(String otherPhone) {
        this.otherPhone = otherPhone;
    }

    public String getWebSite() {
        return webSite;
    }

    public void setWebSite(String webSite) {
        this.webSite = webSite;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getAddressName() {
        return addressName;
    }

    public void setAddressName(String addressName) {
        this.addressName = addressName;
    }

    public String getAddressLine1() {
        return addressLine1;
    }

    public void setAddressLine1(String addressLine1) {
        this.addressLine1 = addressLine1;
    }

    public String getAddressLine2() {
        return addressLine2;
    }

    public void setAddressLine2(String addressLine2) {
        this.addressLine2 = addressLine2;
    }

    public String getAddressLine3() {
        return addressLine3;
    }

    public void setAddressLine3(String addressLine3) {
        this.addressLine3 = addressLine3;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getPostalCode() {
        return postalCode;
    }

    public void setPostalCode(String postalCode) {
        this.postalCode = postalCode;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getAddressType() {
        return addressType;
    }

    public void setAddressType(String addressType) {
        this.addressType = addressType;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Account Id: ").append(getAccountId()).append(", ");
        sb.append("Account Name: ").append(getAccountName()).append(", ");
        sb.append("Account Number: ").append(getAccountNumber());

        return sb.toString();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((accountName == null) ? 0 : accountName.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof Account)) {
            return false;
        }
        Account other = (Account) obj;
        if (accountId == null) {
            if (other.accountId != null) {
                return false;
            }
        } else if (!accountId.equals(other.accountId)) {
            return false;
        }
        if (accountName == null) {
            if (other.accountName != null) {
                return false;
            }
        } else if (!accountName.equals(other.accountName)) {
            return false;
        }
        if (accountNumber == null) {
            if (other.accountNumber != null) {
                return false;
            }
        } else if (!accountNumber.equals(other.accountNumber)) {
            return false;
        }
        return true;
    }
}
